/*
 *  Copyright (c) Iris Dev. team. All rights reserved.
 *  See http://www.communico.pro/license for details.
 *
 */
#ifndef _AS_MEMCACHED_HPP__
#define _AS_MEMCACHED_HPP__ 1

#include <ASTypes.hpp>
#include <STLString.hpp>

namespace CAS_MOD
{

/**
  @struct Memcached ASMemcachedImpl.hpp <ASMemcachedImpl.hpp>
  @brief Memcached TCP protocol implementation
*/
class Memcached
{
public:
	enum eQueryResult { OK             = 0,
	                    BAD_COMMAND    = -1,
	                    NOT_CONNECTED  = -2,
	                    SERVER_TIMEOUT = -3,
	                    NOT_EXISTS     = -4,
	                    EXISTS         = -5,
	                    CLIENT_ERROR   = -6,
	                    PROTOCOL_ERROR = -7 };

	/**
	  @brief Constructor
	  @param sHost - memcached host or IP address or unix socket
	  @param iPort - memcached port
	  @param iProto - protocol: TCP or UDP, default 0 (TCP)
	  @param iConnectTimeout - connection timeout, msec
	  @param iIOTimeout - Input/Output timeout, msec
	*/
	Memcached(const STLW::string  & sHost,
	          INT_32                iPort,
	          INT_32                iProto          = 0,
	          INT_32                iConnectTimeout = 1000,
	          INT_32                iIOTimeout      = 1000);

	/**
	  @brief Get value from memcached
	  @param sKey - key to get
	  @param sValue - output value
	  @param iFlags - memcached flags
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Get(const STLW::string  & sKey,
	                 STLW::string        & sValue,
	                 UINT_64             & iFlags);

	/**
	  @brief Get value from memcached
	  @param sKey - key to get
	  @param sValue - output value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Get(const STLW::string  & sKey,
	                 STLW::string        & sValue);

	/**
	  @brief Get value from memcached
	  @param sKey - key to get
	  @param sValue - output value
	  @param iFlags - memcached flags
	  @param iCASUnique - CAS unique value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Gets(const STLW::string  & sKey,
	                  STLW::string        & sValue,
	                  UINT_64             & iFlags,
	                  UINT_64             & iCASUnique);

	/**
	  @brief Get value from memcached
	  @param sKey - key to get
	  @param sValue - output value
	  @param iCASUnique - CAS unique value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Gets(const STLW::string  & sKey,
	                  STLW::string        & sValue,
	                  UINT_64             & iCASUnique);

	/**
	  @brief Set value
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Set(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 const UINT_64       & iFlags,
	                 INT_32                iExpires = 0);

	/**
	  @brief Set value
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Set(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 INT_32                iExpires = 0);

	/**
	  @brief Set value
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Add(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 const UINT_64       & iFlags,
	                 INT_32                iExpires = 0);

	/**
	  @brief Set value
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Add(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 INT_32                iExpires = 0);

	/**
	  @brief Increment/add value
	  @param sKey - memcached key
	  @param iValue - value to increment
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Incr(const STLW::string  & sKey,
	                  INT_64              & iValue);

	/**
	  @brief Decrement/substract value
	  @param sKey - memcached key
	  @param iValue - value to decrement
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Decr(const STLW::string  & sKey,
	                  INT_64              & iValue);

	/**
	  @brief Replace value
	  @param sKey - memcached key
	  @param sValue - value to replace
	  @param iFlags - memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Replace(const STLW::string  & sKey,
	                     const STLW::string  & sValue,
	                     const UINT_64       & iFlags,
	                     INT_32                iExpires = 0);

	/**
	  @brief Replace value
	  @param sKey - memcached key
	  @param sValue - value to replace
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Replace(const STLW::string  & sKey,
	                     const STLW::string  & sValue,
	                     INT_32                iExpires = 0);

	/**
	  @brief Append data to string stored in cache
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Append(const STLW::string  & sKey,
	                    const STLW::string  & sValue,
	                    const UINT_64       & iFlags,
	                    INT_32                iExpires = 0);

	/**
	  @brief Append data to string stored in cache
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Append(const STLW::string  & sKey,
	                    const STLW::string  & sValue,
	                    INT_32                iExpires = 0);

	/**
	  @brief Prepend value to string stored in cache
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Prepend(const STLW::string  & sKey,
	                     const STLW::string  & sValue,
	                     const UINT_64       & iFlags,
	                     INT_32                iExpires = 0);

	/**
	  @brief Prepend value to string stored in cache
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Prepend(const STLW::string  & sKey,
	                     const STLW::string  & sValue,
	                     INT_32                iExpires = 0);

	/**
	  @brief Delete value from cache
	  @param sKey - memcached key
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Del(const STLW::string & sKey);

	/**
	  @brief Check And Set
	  @param sKey - key
	  @param sValue - value to set
	  @param iCASUnique - CAS unique value
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Cas(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 const UINT_64       & iCASUnique,
	                 INT_32                iExpires = 0);

	/**
	  @brief Check And Set
	  @param sKey - key
	  @param sValue - value to set
	  @param iCASUnique - CAS unique value
	  @param iFlags - Memcached flags
	  @param iExpires - expiration time
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult Cas(const STLW::string  & sKey,
	                 const STLW::string  & sValue,
	                 const UINT_64       & iCASUnique,
	                 const UINT_64       & iFlags,
	                 INT_32                iExpires = 0);

	/**
	  @brief Connect to memcached server
	  @return Connection status: SERVER_TIMEOUT, CLIENT_ERROR or OK
	*/
	eQueryResult Connect();

	/**
	  @brief Disconnect from memcached server
	  @return OK
	*/
	eQueryResult Disconnect();

	/**
	  @brief Disconnect & Connect
	  @return Connection status: SERVER_TIMEOUT, CLIENT_ERROR or OK
	*/
	eQueryResult Reconnect();

	/**
	  @return Connection status: OK or CLIENT_ERROR
	*/
	eQueryResult IsConnected();

	/**
	  @brief Get Unix error code
	*/
	INT_32 GetError();

	/**
	  @brief A destructor
	*/
	~Memcached() throw();
private:
	/** Host                  */
	const STLW::string    sHost;
	/** Port                  */
	INT_32                iPort;
	/** Proto, TCP ONLY       */
	INT_32                iProto;
	/** IP Address            */
	STLW::string          sIP;
	/** Connection timeout    */
	INT_32                iConnectTimeout;
	/** Input/Output timeout  */
	INT_32                iIOTimeout;
	/** Socket                */
	INT_32                iSocket;
	/** Unix error            */
	INT_32                iError;

	/**
	  @brief Set/replace/append/prepend/add value
	  @param sMethod - method name
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - flags
	  @param iExpires - expiration time
	  @param iCASUnique - CAS unique value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult MemcachedSet(CCHAR_P               sMethod,
	                          const STLW::string  & sKey,
	                          const STLW::string  & sValue,
	                          const UINT_64       & iFlags,
	                          INT_32                iExpires,
	                          const UINT_64       & iCASUnique);

	/**
	  @brief Get value
	  @param sMethod - method name
	  @param sKey - memcached key
	  @param sValue - value to set
	  @param iFlags - Memcached flags
	  @param iCASUnique - CAS unique value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult MemcachedGet(CCHAR_P               sMethod,
	                          const STLW::string  & sKey,
	                          STLW::string        & sValue,
	                          UINT_64             & iFlags,
	                          UINT_64             & iCASUnique);

	/**
	  @brief Increment/decrement value
	  @param sMethod - method name
	  @param iValue - value
	  @return Result of query, one of eQueryResult states
	*/
	eQueryResult MemcachedMath(CCHAR_P               sMethod,
	                           const STLW::string  & sKey,
	                           INT_64              & iValue);

	/**
	  @brief Poll socket
	  @param iFlags - poll function flags
	  @param iTimeout - timeout
	  @return Connection status: SERVER_TIMEOUT, CLIENT_ERROR or OK
	*/
	eQueryResult PollSocket(INT_32  iFlags,
	                        INT_32  iTimeout);

	/**
	  @brief connect to memcached server
	  @return Connection status: SERVER_TIMEOUT, CLIENT_ERROR or OK
	*/
	eQueryResult RealConnect();
};

} // namespace CAS_MOD
#endif // _AS_MEMCACHED_HPP__
// End.

